// ============================================
// cmd/vmctl/commands/console_extended.go
// ============================================

package commands

import (
	"encoding/json"
	"fmt"
	"os/exec"
	"strings"

	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

func NewConsoleCommand(logger *logrus.Logger) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "console",
		Short: "Connect to VM console",
		Long:  "Connect to virtual machine serial, VNC, or SPICE console",
	}

	cmd.AddCommand(
		newConsoleSerialCommand(logger),
		newConsoleVNCCommand(logger),
		newConsoleSPICECommand(logger),
	)

	return cmd
}

// vmctl console vnc <vm>
func newConsoleVNCCommand(logger *logrus.Logger) *cobra.Command {
	var (
		connID string
		viewer string
	)

	cmd := &cobra.Command{
		Use:   "vnc <vm-name>",
		Short: "Connect to VNC console",
		Args:  cobra.ExactArgs(1),
		Long: `Connect to VNC console using external viewer.

Requires a VNC viewer to be installed:
  - vncviewer (TigerVNC)
  - vinagre (GNOME)
  - krdc (KDE)
  - Remote Desktop (macOS)`,
		Example: `  vmctl console vnc ubuntu-vm
  vmctl console vnc ubuntu-vm --viewer vncviewer`,
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			vmName := args[0]

			// 获取 VNC 信息
			ctx := cmd.Context()
			resp, err := apiClient.Get(ctx,
				fmt.Sprintf("/api/v1/console/vnc/%s/%s/info", connID, vmName))
			if err != nil {
				return fmt.Errorf("failed to get VNC info: %w", err)
			}

			var result struct {
				Data struct {
					ProxyURL string `json:"proxy_url"`
					WSPath   string `json:"ws_path"`
					Token    string `json:"token"`
				} `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			fmt.Printf("VNC Console Information:\n")
			fmt.Printf("  Proxy URL: %s\n", result.Data.ProxyURL)
			fmt.Printf("  WebSocket: %s\n", result.Data.WSPath)
			fmt.Println()

			// 如果指定了查看器，启动它
			if viewer != "" {
				vncURL := result.Data.ProxyURL
				fmt.Printf("Opening VNC viewer: %s %s\n", viewer, vncURL)

				cmd := exec.Command(viewer, vncURL)
				if err := cmd.Start(); err != nil {
					return fmt.Errorf("failed to start VNC viewer: %w", err)
				}

				fmt.Println("✓ VNC viewer launched")
			} else {
				fmt.Println("Use a VNC viewer to connect to the above URL")
				fmt.Println("Or use: vmctl console vnc <vm> --viewer vncviewer")
			}

			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	cmd.Flags().StringVar(&viewer, "viewer", "", "VNC viewer command (vncviewer, vinagre, etc.)")
	return cmd
}

// vmctl console serial <vm>
func newConsoleSerialCommand(logger *logrus.Logger) *cobra.Command {
	var (
		connID      string
		interactive bool
	)

	cmd := &cobra.Command{
		Use:   "serial <vm-name>",
		Short: "Connect to serial console",
		Args:  cobra.ExactArgs(1),
		Long: `Connect to virtual machine serial console.

This command connects to the serial console of a virtual machine.
Serial console provides text-based access to the VM's console output.

In interactive mode, it will automatically connect to the WebSocket console
and provide a terminal interface for interacting with the VM.`,
		Example: `  # Display serial console information
  vmctl console serial ubuntu-vm

  # Interactive mode - connect directly to serial console
  vmctl console serial ubuntu-vm --interactive

  # With specific connection
  vmctl console serial ubuntu-vm --connection conn-id --interactive`,
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			vmName := args[0]

			// 获取串口控制台信息
			ctx := cmd.Context()
			resp, err := apiClient.Get(ctx,
				fmt.Sprintf("/api/v1/console/serial/%s/%s/info", connID, vmName))
			if err != nil {
				return fmt.Errorf("failed to get serial console info: %w", err)
			}

			var result struct {
				Data struct {
					ProxyURL string `json:"proxy_url"`
					WSPath   string `json:"ws_path"`
					Token    string `json:"token"`
				} `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			fmt.Printf("Serial Console Information:\n")
			fmt.Printf("  Proxy URL: %s\n", result.Data.ProxyURL)
			fmt.Printf("  WebSocket: %s\n", result.Data.WSPath)
			fmt.Println()

			if interactive {
				// 交互式模式：直接连接到 WebSocket 控制台
				if result.Data.WSPath == "" {
					return fmt.Errorf("WebSocket path not available for serial console")
				}

				fmt.Println("Connecting to serial console in interactive mode...")

				// 构建完整的 WebSocket URL
				wsURL, err := buildWebSocketURL(apiClient, result.Data.WSPath, result.Data.Token)
				if err != nil {
					return fmt.Errorf("failed to build WebSocket URL: %w", err)
				}

				// 运行 WebSocket 客户端
				return RunSerialConsole(wsURL, logger)
			} else {
				// 非交互式模式：显示连接信息
				fmt.Println("To connect to the serial console:")
				fmt.Println("  - Use a WebSocket client to connect to the WebSocket path above")
				fmt.Println("  - Or use: vmctl console serial <vm> --interactive")
			}

			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	cmd.Flags().BoolVarP(&interactive, "interactive", "i", false, "Interactive mode - connect directly to serial console")
	return cmd
}

// buildWebSocketURL 构建完整的 WebSocket URL
func buildWebSocketURL(apiClient any, wsPath string, token string) (string, error) {
	// 如果已经是完整的 URL（以 ws:// 或 wss:// 开头），直接返回
	if len(wsPath) >= 5 && (wsPath[:5] == "ws://" || wsPath[:6] == "wss://") {
		if token != "" {
			return wsPath + "?token=" + token, nil
		}
		return wsPath, nil
	}

	// 获取服务器的基础 URL
	var baseURL string
	if getServerURLFunc != nil {
		baseURL = getServerURLFunc()
	} else {
		baseURL = "http://localhost:8080"
	}

	// 将 HTTP URL 转换为 WebSocket URL
	if len(baseURL) >= 7 && baseURL[:7] == "http://" {
		baseURL = "ws://" + baseURL[7:]
	} else if len(baseURL) >= 8 && baseURL[:8] == "https://" {
		baseURL = "wss://" + baseURL[8:]
	}

	// 确保路径以 / 开头
	if wsPath != "" && wsPath[0] != '/' {
		wsPath = "/" + wsPath
	}

	fullURL := baseURL + wsPath
	if token != "" {
		if strings.Contains(fullURL, "?") {
			fullURL += "&token=" + token
		} else {
			fullURL += "?token=" + token
		}
	}

	return fullURL, nil
}

// vmctl console spice <vm>
func newConsoleSPICECommand(logger *logrus.Logger) *cobra.Command {
	var (
		connID string
		viewer string
	)

	cmd := &cobra.Command{
		Use:   "spice <vm-name>",
		Short: "Connect to SPICE console",
		Args:  cobra.ExactArgs(1),
		Long: `Connect to SPICE console using external viewer.

Requires a SPICE client to be installed:
  - remote-viewer (virt-viewer)
  - spicy (spice-gtk)`,
		Example: `  vmctl console spice ubuntu-vm
  vmctl console spice ubuntu-vm --viewer remote-viewer`,
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			vmName := args[0]

			// 获取 SPICE 信息
			ctx := cmd.Context()
			resp, err := apiClient.Get(ctx,
				fmt.Sprintf("/api/v1/console/spice/%s/%s/info", connID, vmName))
			if err != nil {
				return fmt.Errorf("failed to get SPICE info: %w", err)
			}

			var result struct {
				Data struct {
					ProxyURL string `json:"proxy_url"`
					WSPath   string `json:"ws_path"`
					Token    string `json:"token"`
				} `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			fmt.Printf("SPICE Console Information:\n")
			fmt.Printf("  Proxy URL: %s\n", result.Data.ProxyURL)
			fmt.Printf("  WebSocket: %s\n", result.Data.WSPath)
			fmt.Println()

			// 如果指定了查看器，启动它
			if viewer != "" {
				spiceURL := result.Data.ProxyURL
				fmt.Printf("Opening SPICE viewer: %s %s\n", viewer, spiceURL)

				cmd := exec.Command(viewer, spiceURL)
				if err := cmd.Start(); err != nil {
					return fmt.Errorf("failed to start SPICE viewer: %w", err)
				}

				fmt.Println("✓ SPICE viewer launched")
			} else {
				fmt.Println("Use a SPICE client to connect to the above URL")
				fmt.Println("Or use: vmctl console spice <vm> --viewer remote-viewer")
			}

			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	cmd.Flags().StringVar(&viewer, "viewer", "", "SPICE viewer command (remote-viewer, spicy, etc.)")
	return cmd
}
